package parser;


import java.io.*;
import java.util.*;
import java.net.URL;

import utils.EDCResource;

import com.wutka.dtd.*;

/**
 * Deprecated !
 * This class is not used any more.
 */


/*
 *  Logical language to describe properties?
 *  
 *  Syntaxe :
 *  boolean operators :
 *  	or	: ||
 *  	and	: &&
 *  	not	: !!
 *  elements/attributes :
 *  	any	: _
 *  	var	: [a-z]
 *  cardinal : 
 *  	optional : ??
 *  	zeromany : **
 *  	onemany  : ++
 *  
 *  Contenu : !!(EMPTY) && !!(ANY)
 *  Sequence : !!(_**, a, _**, a++, _**)
 *  Choice : (_^** | _^**)*
 *  
 *  
 */



public class Tokenize{
	
	public static String sep = File.pathSeparator;
	public static int currentDTDIndex;
	/*
	 * Number of rows for properties
	 * Change this value to add new properties
	 */
	public static int nbStatsCols = 5;
	public static ArrayList<Integer> badDTDs;
	public static ArrayList<String> dtdNames;
	/*
	 * stats: double entry array which contains statistics about the violations to the rules 
	 * Lines: dtd files
	 * Rows: Property to check
	 */
	public static int[][] stats;
	// stats[] = { TotalBadLines, ANY, EMPTY, Redundancy, BadChoice }
	public static int totalBadFiles = 0;
	
	/*
	 * Visits an Item of a DTD File and checks properties required
	 */
	public static boolean dumpDTDItem(DTDItem item, Vector<String> elements) {
		return dumpDTDItem(item, elements, false);
	}
	
	/*
	 * boolean isInChoice indicates whether this item is in a choice 
	 */
    public static boolean dumpDTDItem(DTDItem item, Vector<String> elements, boolean isInChoice) {
    	boolean isOK = true;
    	boolean isChoice = false;
    	
        if (item == null)
        	return true;
        
        if (item instanceof DTDAny) {
            //System.out.print("Any");
            isOK = false;
            stats[currentDTDIndex][1]++;
        }
        else if (item instanceof DTDEmpty) {
            //System.out.print("Empty");
            isOK = false;
            stats[currentDTDIndex][2]++;
        }
        else if (item instanceof DTDName) {
        	String name = ((DTDName) item).value;
        	if (elements.contains(name)) {
        		isOK = false;
                stats[currentDTDIndex][3]++;
        	}
        	else
        		elements.add(name);
            //System.out.print(name);
        }
        else if (item instanceof DTDChoice) {
            //System.out.print("(");
        	isChoice = true;
            DTDItem[] items = ((DTDChoice) item).getItems();
            
            for (int i=0; i < items.length; i++) {
            	/*
                if (i > 0)
                	System.out.print("|");
            	*/
                isOK = dumpDTDItem(items[i], elements, true);
            }
            //System.out.print(")");
        }
        else if (item instanceof DTDSequence) {
            //System.out.print("(");
            DTDItem[] items = ((DTDSequence) item).getItems();
            
            for (int i=0; i < items.length; i++) {
            	/*
                if (i > 0)
                	System.out.print(",");
                */
                isOK = dumpDTDItem(items[i], elements);
            }
            //System.out.print(")");
        }
        else if (item instanceof DTDMixed) {
            //System.out.print("(");
            DTDItem[] items = ((DTDMixed) item).getItems();
            
            for (int i=0; i < items.length; i++) {
            	/*
                if (i > 0)
                	System.out.print(",");
                */
                isOK = dumpDTDItem(items[i], elements);
            }
            //System.out.print(")");
        }
        else if (item instanceof DTDPCData) {
            //System.out.print("#PCDATA");
        }
        
        if (item.cardinal == DTDCardinal.OPTIONAL) {
            //System.out.print("?");
        	if (isChoice) {
        		isOK = false;
                stats[currentDTDIndex][4]++;
        	}
        }
        else if (item.cardinal == DTDCardinal.ZEROMANY) {
            //System.out.print("*");
        	if (isInChoice) {
        		isOK = false;
                stats[currentDTDIndex][4]++;
        	}
        }
        else if (item.cardinal == DTDCardinal.ONEMANY) {
            //System.out.print("+");
        	if (isInChoice) {
        		isOK = false;
                stats[currentDTDIndex][4]++;
        	}
        } else {
        	// There is no cardinal
        	if (isChoice) {
        		isOK = false;
                stats[currentDTDIndex][4]++;
        	}
        }
        
        return isOK;
    }

    public static boolean dumpAttribute(DTDAttribute attr) {
    	/*
    	 * Uncomment requested parts of this code to check properties on attributes 
    	 *  
        System.out.print(attr.name+" ");
        if (attr.type instanceof String) {
            System.out.print(attr.type);
        } else if (attr.type instanceof DTDEnumeration) {
            System.out.print("(");
            String[] items = ((DTDEnumeration) attr.type).getItems();

            for (int i=0; i < items.length; i++) {
                if (i > 0)
                	System.out.print(",");
                System.out.print(items[i]);
            }
            System.out.print(")");
        }
        else if (attr.type instanceof DTDNotationList) {
            System.out.print("Notation (");
            String[] items = ((DTDNotationList) attr.type).getItems();

            for (int i=0; i < items.length; i++) {
                if (i > 0)
                	System.out.print(",");
                System.out.print(items[i]);
            }
            System.out.print(")");
        }

        if (attr.decl != null) {
            System.out.print(" "+attr.decl.name);
        }

        if (attr.defaultValue != null) {
            System.out.print(" "+attr.defaultValue);
        }

        System.out.println();
        */
        return true;
    }
    
	/**
	 * @param fileName The DTD file to check
	 * 
	 * This method checks all the properties defined on the DTD
	 * 	 
	 * */
	public static boolean checkDTD(String fileName) {
		try {
            DTDParser parser = null;
            boolean isOK = true;
			// MAW Version 1.17
			// If it looks like the filename may be a URL, use the URL class
            if (fileName.indexOf("://") > 0) {
                parser = new DTDParser(new URL(fileName));
            } else {
                parser = new DTDParser(new File(fileName));
            }

            // Parse the DTD and ask the parser to guess the root element
            DTD dtd = parser.parse(true);
            
            /*
            if (dtd.rootElement != null) {
               System.out.println("Root element is probably: " + dtd.rootElement.name);
            }
            */
            
            @SuppressWarnings("unchecked")
            Enumeration e = dtd.elements.elements();
            
            Vector<String> elements = new Vector<String>();
            while (e.hasMoreElements()) {
                DTDElement elem = (DTDElement) e.nextElement();
                
                /*
                System.out.println("Element: "+elem.name);
                System.out.print("   Content: ");
                */
                
                elements.clear();
                
                if (!dumpDTDItem(elem.content, elements)) {
                	isOK = false;
                	// this DTD's definition is "bad", we increase the number of "bad" lines 
                	stats[currentDTDIndex][0]++;
                }
                
                /*
                //System.out.println();
                 
                if (elem.attributes.size() > 0) {
                    //System.out.println("   Attributes: ");
                    @SuppressWarnings("unchecked")
                    Enumeration attrs = elem.attributes.elements();
                    while (attrs.hasMoreElements()) {
                        //System.out.print("        ");
                        DTDAttribute attr = (DTDAttribute) attrs.nextElement();
                        dumpAttribute(attr);
                    }
                    // System.out.println();
                }
                */
            }
            
            return isOK;
            /*
            e = dtd.entities.elements();
            while (e.hasMoreElements()) {
                DTDEntity entity = (DTDEntity) e.nextElement();
                
                if (entity.isParsed)
                	System.out.print("Parsed ");

                System.out.println("Entity: "+entity.name);
                
                if (entity.value != null) {
                    System.out.println("    Value: "+entity.value);
                }
                
                if (entity.externalID != null) {
                    if (entity.externalID instanceof DTDSystem) {
                        System.out.println("    System: "+ entity.externalID.system);
                    } else {
                        DTDPublic pub = (DTDPublic) entity.externalID;
                        System.out.println("    Public: "+ pub.pub+" "+pub.system);
                    }
                }

                if (entity.ndata != null) {
                    System.out.println("    NDATA "+entity.ndata);
                }
            }
			
            e = dtd.notations.elements();
            while (e.hasMoreElements()) {
                DTDNotation notation = (DTDNotation) e.nextElement();

                System.out.println("Notation: "+notation.name);
                
                if (notation.externalID != null) {
                    if (notation.externalID instanceof DTDSystem) {
                        System.out.println("    System: "+ notation.externalID.system);
                    } else {
                        DTDPublic pub = (DTDPublic) notation.externalID;
                        System.out.print("    Public: "+ pub.pub+" ");
                        if (pub.system != null) {
                            System.out.println(pub.system);
                        } else {
                            System.out.println();
                        }
                    }
                }
            }
            */
		}
		catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	
	
	public static void main(String[] args) {
		File f = new File("dtd");
		try {
//			System.out.println(f.getCanonicalPath());
//			System.out.println(f.isDirectory());
			
			File[] dtds = f.listFiles(EDCResource.dtdFilter);
			
			dtdNames = new ArrayList<String>(dtds.length);
			badDTDs = new ArrayList<Integer>(dtds.length/2);
			stats = new int[dtds.length][nbStatsCols];
			
			// initialization of the stats array
			for (int i=0; i<stats.length; i++) {
				for (int j=0; j<stats[i].length; j++) {
					stats[i][j] = 0;
				}
			}
			
			String name;
			for (int i=0; i<dtds.length; i++) {
				currentDTDIndex = i;
				name = dtds[i].getCanonicalPath();
				dtdNames.add(name);
				
				System.out.println(name);
				if (!checkDTD(name)) {
					badDTDs.add(Integer.valueOf(currentDTDIndex));
					totalBadFiles++;
				}
			}
			
			// Display bad files
			System.out.println("There are "+totalBadFiles+" wrong DTDs (out of "+dtds.length+" => "+(float)(totalBadFiles*100/dtds.length)+"% bad):");
			int i;
			for (Integer index : badDTDs) {
				i = index.intValue();
				System.out.print(dtdNames.get(i)+" : ");
				System.out.print(stats[i][0]+" bad lines ; ");
				System.out.print(stats[i][1]+" ANY ; ");
				System.out.print(stats[i][2]+" EMPTY ; ");
				System.out.print(stats[i][3]+" redudancy ; ");
				System.out.println(stats[i][4]+" bad choices.");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
